/** @typedef {Object} Set */

export class Base {

  constructor(config) {
    var events = [], obj = this, i;
    _.each(config, (item, i) => { _.isUndefined(item) || (this[i] = item) });
    this.events = {};
    do {
      obj.events && events.push(obj.events);
    } while (obj = Object.getPrototypeOf(obj));
    i = events.length;
    while (i--) {
      _.each(events[i], (item, evt) => {
        this.events[evt] || (this.events[evt] = new Set);
        for (let fn of item) this.events[evt].add(fn);
      });
    }
  }

  on(evt, fn = () => {}, once = false) {
    this.events[evt] || (this.events[evt] = new Set);
    fn.once = once;
    this.events[evt].add(fn);
  }

  un(evt = null, fn = null) {
    this.events[evt] ? this.events[evt].delete(fn) : (delete this.events);
  }

  fire(evt, ...params) {
    if (this.events[evt]) {
      for (let fn of this.events[evt]) {
        let res = fn(...params);
        fn.once && this.un(evt, fn);
        if (false === res) return res;
      }
    }
    return true;
  }

}

export function props(cls, config) {
  _.each(config, (item, i) => { cls.prototype[i] = item });
}